package main

import (
	"fmt"
	"reflect"
)

// student 结构体
type FunctionStudent struct {
	Name  string `json:"name"`
	Age   int    `json:"age"`
	Score int    `json:"score"`
}

func (s FunctionStudent) GetInfo() string {
	var str = fmt.Sprintf("姓名:%v 年龄:%v 成绩:%v", s.Name, s.Age, s.Score)
	fmt.Println(str)
	return str
}
func (s *FunctionStudent) SetInfo(name string, age int, score int) {
	s.Name = name
	s.Age = age
	s.Score = score
}
func (s *FunctionStudent) PrintFunction() {
	fmt.Println("打印方法...")
}

// 打印字段
func PrintFunctionStructField(s interface{}) {
	t := reflect.TypeOf(s)
	if t.Kind() != reflect.Struct && t.Elem().Kind() != reflect.Struct {
		fmt.Println("传入的不是结构体")
		return
	}
	//1、通过类型变量里面的 Field 可以获取结构体的字段
	field0 := t.Field(0)
	fmt.Println(field0.Name)
	fmt.Println(field0.Type)
	fmt.Println(field0.Tag.Get("json"))
	//2、通过类型变量里面的 FieldByName 可以获取结构体的字段
	field1, _ := t.FieldByName("Age")
	fmt.Println(field1.Name)
	fmt.Println(field1.Type)
	fmt.Println(field1.Tag.Get("json"))
	//3、获取到该结构体有几个字段
	num := t.NumField()
	fmt.Println("字段数量:", num)
}

// 方法
func PrintStructFn(s interface{}) {
	t := reflect.TypeOf(s)
	v := reflect.ValueOf(s)
	if t.Kind() != reflect.Struct && t.Elem().Kind() != reflect.Struct {
		fmt.Println("传入的不是结构体")
		return
	}
	//1、通过类型变量里面的 Method 可以获取结构体的方法
	var tMethod = t.Method(0) //注意
	fmt.Println(tMethod.Name) // GetInfo
	fmt.Println(tMethod.Type) // func(*main.FunctionStudent) string
	//2、通过类型变量获取这个结构体有多少个方法
	fmt.Println(t.NumMethod()) // 3
	//3、执行方法 （注意需要使用值变量，并且要注意参数）
	// v.Method(0).Call(nil)
	v.MethodByName("PrintFunction").Call(nil) // 打印方法.. 执行方法
	//4、执行方法传入参数 （注意需要使用值变量，并且要注意参数）
	var params []reflect.Value //声明了 []reflect.Value
	params = append(params, reflect.ValueOf("张三"))
	params = append(params, reflect.ValueOf(22))
	params = append(params, reflect.ValueOf(100))
	v.MethodByName("SetInfo").Call(params) //传入的参数是 []reflect.Value, 返回[]reflect.Value
	// 5、执行方法获取方法的值
	info := v.MethodByName("GetInfo").Call(nil) // 姓名:张三 年龄:22 成绩:100
	fmt.Println(info)                           // [姓名:张三 年龄:22 成绩:100]
}
func main() {
	stu1 := FunctionStudent{
		Name: "小明", Age: 15, Score: 98}
	PrintFunctionStructField(stu1)

	fmt.Println("=============================")
	PrintStructFn(&stu1)
}
